(** Bombs-Must-Detonate : AST Types 
    @author Brian Go *)

(** SYNTAX TREE *)

(** Field info is annotated by the type checker for use in the IR compiler *)
type field_info = 
    VIdUnspecified (** Not yet set by type checker *)
  | VIdStructField of int (** The field is the (int)th field of the struct *)
  | VIdEnumValue of int (** The field is the (int)th value of an enum *)

(** Top-level expressions *)
type global_expression =
    SynFunctionDeclare of function_declare
  | SynRemotableFunctionDeclare of function_declare
  | SynTemplatedDeclare of string list * global_expression 
  | SynFunctionDefine of function_define
  | SynTemplatedDefine of string list * global_expression
  | SynStructDeclare of struct_declare
  | SynGlobalEnumDeclare of enum_declare
  | SynGlobalVarDeclare of var_declare
  | SynInclude of include_data ref
  | SynStateMachine of fsm_state_machine

(** The include string is replaced by an AST so as to only parse it once *)
and include_data =
    IncludeFileName of string
  | IncludeAst of global_expression list

(** Expressions *)
and expression = 
    SynVarDeclare of var_declare
  | SynEnumDeclare of enum_declare
  | SynVarAssign of var_assign
  | SynCond of conditional
  | SynLoop of loop
  | SynFunctionCall of function_call
  | SynReturnStatement of return_statement
  | SynBreak (** Produces a type error if not in a loop *)
  | SynContinue (** Produces a type error if not in a loop *)

(** Functions *)
and function_declare = 
    data_type * string * (data_type * string) list (** return type, name, arg list *)
and function_define = function_declare * expression list (** declaration, body *)
and function_call = 
    SynLocalCall of string * value_producer list * bool ref (** name, args, true if it is a variable-function *)
  | SynRemoteCall of 
      string * value_producer list * var_ident (** name, args, return value target variable *)
  | SynRemoteCallNoResult of
      string * value_producer list (** name, args *)
and return_statement = 
    SynVoidReturn
  | SynValueReturn of value_producer

(** Data Structures *)
and struct_declare = string * var_declare list (** name, fields *)
and enum_declare = string * string list (** name, values *)

(** Variables *)
and var_declare = 
    SynVarDeclareNoInit of data_type * string (** type, name *)
  | SynVarDeclareWithInit of 
      data_type * string * value_producer (** type, name, initial value *)
and var_assign = 
    SynVarAssignment of var_ident * value_producer (** var_ident = value_producer *)
  | SynVarModify of var_ident * binop * value_producer (** e.g. +=,*=.  for cons (::=), the list is on the LHS *)

(** Conditionals *)
and conditional = 
    SynIf of value_producer * expression list 
  | SynIfCase of value_producer 
      * expression list * continued_conditional
and continued_conditional = 
    SynFinalElse of expression list
  | SynElse of conditional

(** Loops *)
and loop =
    SynWhile of value_producer * expression list
  | SynFor of expression * value_producer * expression
      * expression list (** init, test, step, body.  Note: step expression must end in a semicolon *)
  | SynDoWhile of expression list * value_producer

(** Value Producers *)
and value_producer = 
    SynValue of value
  | SynFunctionCallValue of function_call
  | SynVarIdentifier of var_ident
  | SynBinop of value_producer * binop * value_producer
  | SynPrefixUnop of pre_unop * value_producer
  | SynParenthesized of value_producer
  | SynArrayValueProducer of value_producer list
  | SynListValueProducer of list_value_producer

and value = 
    SynIntValue of int
  | SynFloatValue of float
  | SynStringValue of string
  | SynBoolValue of bool

and list_value_producer =
    SynListNil of data_type
  | SynListList of value_producer list
  | SynListCons of value_producer * value_producer (** car, cdr *)

and var_ident =
    SynVarName of string
  | SynStructOrEnumValue of var_ident * string * field_info ref (** field info set by type checker for use by IR compiler *)
  | SynArrayCell of var_ident * value_producer

(** Data Types *)
and data_type = 
    SynIntType
  | SynFloatType
  | SynStringType
  | SynBoolType
  | SynVoidType
  | SynEnumOrStructType of string * (data_type list) ref (** field types set by type checker for use by IR compiler *)
  | SynArrayType of data_type * value_producer
  | SynListType of data_type
  | SynRefType of data_type
  | SynArrowType of data_type list * data_type (** arg types, return type  *)

(** Operators *)
and binop =
  | SynBinopAnd
  | SynBinopOr
  | SynBinopAdd
  | SynBinopSub
  | SynBinopMul
  | SynBinopDiv
  | SynBinopIDiv
  | SynBinopMod
  | SynBinopConcat
  | SynBinopCons
  | SynCompLt
  | SynCompGt
  | SynCompLte
  | SynCompGte
  | SynCompEq
  | SynCompNeq

and pre_unop = 
  | SynUnopNot
  | SynUnopCar
  | SynUnopCdr
  | SynUnopTrunc
  | SynUnopDeref
  | SynUnopNeg
  | SynUnopNull

(** State Machine Syntax *)
and fsm_state_machine = string * string * fsm_state list (** name, onInit handler, state list *)
and fsm_state = string * fsm_callback list * fsm_transition list (** name, callbacks, transitions *)
and fsm_callback = 
    SynFsmOnInit of string (** This is not actually a callback but is executed every time the state is visited *)
  | SynFsmOnMoveRequest of string
  | SynFsmOnTeammateDeath of string
  | SynFsmOnBombDetonate of string
  | SynFsmOnDeath of string

and fsm_transition = string list * (string * float) list

and src_program = global_expression list

(** Pretty print the AST *)
val print_ast : src_program -> unit

(** Pretty-printable string of the AST *)
val string_of_ast : src_program -> string 

(** Pretty-printable string of a binary operator *)
val string_of_binop: binop -> string
